/*
 * rfid_utils.c
 * NOTE: Please also check the comments in rfid_utils.h
 * they provide useful hints and background information.
 */
#include "rfid_utils.h"
#include "framework.h"

/****************************************
 * Private variables
 ****************************************/
#define DEBUGOUT dbg_print

// rfid_block_buff used to store the read end write data, each block have 16 bytes,
// rfid_block_buff must have 18 slots, see MIFARE_Read()
static uint8_t rfid_block_buff[20];
static uint8_t size = sizeof(rfid_block_buff);

// return status from MFRC522 functions
static StatusCode status;

/****************************************
 * Private Functions
 ****************************************/

/**
 * Read 16 bytes from a block inside a sector
 * @param  mfrc522   MFRC522 ADT pointer
 * @param  sector    card sector, 0 to 15
 * @param  block_addr card block address, 0 to 63
 * @return           0 is no error, -1 is authentication error -2 is read error
 */
static int readCardBlock(MFRC522Ptr_t mfrc522, uint8_t sector, uint8_t block_addr)
{

	MIFARE_Key key;
	int i;
	// using FFFFFFFFFFFFh which is the default at chip delivery from the
	// factory
	for (i = 0; i < 6; i++)
	{
		key.keybyte[i] = 0xFF;
	}

	// Authenticate using key A
	status = (StatusCode)PCD_Authenticate(mfrc522, PICC_CMD_MF_AUTH_KEY_A,
										  block_addr, &key, &(mfrc522->uid));
	if (status != STATUS_OK)
	{
		DEBUGOUT("PCD_Authenticate() failed: ");
		DEBUGOUT(GetStatusCodeName(status));
		return -1;
	}

	// Read data from the block
	status = (StatusCode)MIFARE_Read(mfrc522, block_addr, rfid_block_buff, &size);
	if (status == STATUS_OK)
	{
		dbg_print("\nic card block read : addr :%d:", block_addr);
		dbg_u8_print("\n", rfid_block_buff, 16, 16);
	}
	else
	{
		DEBUGOUT("MIFARE_Read() failed: ");
		DEBUGOUT(GetStatusCodeName(status));
		return -2;
	}

	// Halt PICC
	//PICC_HaltA(mfrc522);
	// Stop encryption on PCD
	//PCD_StopCrypto1(mfrc522);

	return 0;
}

/**
 * Write 16 bytes to a block inside a sector
 * @param  mfrc522   MFRC522 ADT pointer
 * @param  sector    card sector, 0 to 15
 * @param  block_addr card block address, 0 to 63
 * @return           0 is no error, -1 is authentication error -2 is write error
 */
static int writeCardBlock(MFRC522Ptr_t mfrc522, uint8_t sector, uint8_t block_addr)
{
	MIFARE_Key key;
	int i;
	// using FFFFFFFFFFFF which is the default at chip delivery from the factory
	for (i = 0; i < 6; i++)
	{
		key.keybyte[i] = 0xFF;
	}

	// Authenticate using key A
	status = (StatusCode)PCD_Authenticate(mfrc522, PICC_CMD_MF_AUTH_KEY_A,
										  block_addr, &key, &(mfrc522->uid));
	if (status != STATUS_OK)
	{
		DEBUGOUT("PCD_Authenticate() failed: ");
		DEBUGOUT(GetStatusCodeName(status));
		return -1;
	}

	dbg_print("\nic card block write : addr :%d:", block_addr);
	
	// Write data from the block, always write 16 bytes
	status = (StatusCode)MIFARE_Write(mfrc522, block_addr, rfid_block_buff, 16);
	if (status != STATUS_OK)
	{
		DEBUGOUT("MIFARE_Write() failed: ");
		DEBUGOUT(GetStatusCodeName(status));
		return -2;
	}
	else
	{
		DEBUGOUT("MIFARE_Write() ok: ");
	}

	// Halt PICC
	//PICC_HaltA(mfrc522);
	// Stop encryption on PCD
	//PCD_StopCrypto1(mfrc522);

	return 0;
}

/****************************************
 * Public Functions
 ****************************************/
void setupRFID(MFRC522Ptr_t mfrc522)
{

	PCD_Init(mfrc522, 0);
	DEBUGOUT("\nReader 2 ");

	// Show details of PCD - MFRC522 Card Reader details
	PCD_DumpVersionToSerial(mfrc522);
}

/**
 * Function to read the balance, the balance is stored in the block 4 (sector
 * 1), the first 4 bytes
 * @param  mfrc522 MFRC522 ADT pointer
 * @return         the balance is stored in the PICC, -999 for reading errors
 */
int readCardBalance(MFRC522Ptr_t mfrc522)
{
	int balance;

	int readStatus = readCardBlock(mfrc522, 1, 0);

	readStatus = readCardBlock(mfrc522, 1, 4);
	
	if (readStatus == 0)
	{
		// convert the balance bytes to an integer, byte[0] is the MSB
		balance = (int)rfid_block_buff[3] | (int)(rfid_block_buff[2] << 8) |
				  (int)(rfid_block_buff[1] << 16) | (int)(rfid_block_buff[0] << 24);
	}
	else
	{
		balance = -999;
	}

	// Halt PICC
	PICC_HaltA(mfrc522);
	// Stop encryption on PCD
	PCD_StopCrypto1(mfrc522);
	
	return balance;
}

/**
 * Function to rwrite the balance, the balance is stored in the block 4 (sector
 * 1), the first 4 bytes
 * @param  mfrc522    MFRC522 ADT pointer
 * @param  newBalance the balance to be write  i  the card
 * @return            0 is no errors
 */
int writeCardBalance(MFRC522Ptr_t mfrc522, int newBalance)
{
	int readStatus = readCardBlock(mfrc522, 1, 0);

	int writeStatus = writeCardBlock(mfrc522, 1, 4);

	// Halt PICC
	PICC_HaltA(mfrc522);
	// Stop encryption on PCD
	PCD_StopCrypto1(mfrc522);
	
	return writeStatus;
}
